import asyncio
import datetime
import logging
import os
import random
import time
import sys
from collections.abc import Coroutine

# noinspection PyUnresolvedReferences
import setup_logger
from util.timetool import valid_sign_time, timestamp_to_text

from data.userData import users
from yiban import Yiban
from notice import Notice, ServerChan, Dreamix, DreamixDingtalkGroup
from util.timetool import wait_until_specific_hour
from util.maptool import generate_sign_data_by_userconfig

logger = logging.getLogger("main")


async def create_user_task(user: dict):
    notice = Notice("")
    if not user.get("serverChan") is None:
        notice = ServerChan(user.get("serverChan"))
    if not user.get("dreamix") is None:
        notice = Dreamix(user.get("dreamix"))
    if not user.get("dreamix_dingtalk_group") is None:
        temp = user.get("dreamix_dingtalk_group")
        notice = DreamixDingtalkGroup(temp["token"], temp["group_id"])
    retryCount = 3
    while retryCount > 0:
        retryCount -= 1
        try:
            async with Yiban(user["phone"], user["password"], logger, "./data/user_cache") as yb:
                yb.log.info("登录成功")
                # 登录信息过期提醒
                if datetime.timedelta(days=14) < datetime.datetime.now() - yb.get_login_time() < datetime.timedelta(days=16):
                    yb.log.warning("登录信息即将过期")
                    await notice.send(f'{yb.get_user_name()} 登录信息即将过期，明天可能需要验证码', importance=2)
                await wait_loop(yb, notice, user)  # 进入签到检测处理循环
                break
        except Exception as ex:
            await notice.send(f'{user.get("phone", "???")} {ex}')
            logger.error(ex, exc_info=True)
            continue

async def wait_loop(yb: Yiban, notice: Notice, user: dict):
    refresh_sign_task_flag = False
    sign_info = await yb.task_feedback.get_sign_task()
    yb.log.debug(sign_info)
    time_range = sign_info["Range"]
    yb.log.info(f'签到时间为{timestamp_to_text(time_range["StartTime"])}-{timestamp_to_text(time_range["EndTime"])}')
    while True:
        # 刷新时间范围
        if refresh_sign_task_flag:
            refresh_sign_task_flag = False
            sign_info = await yb.task_feedback.get_sign_task()
            time_range = sign_info["Range"]
            yb.log.info(
                f'签到时间为{timestamp_to_text(time_range["StartTime"])}-{timestamp_to_text(time_range["EndTime"])}')
        valid_time_res = valid_sign_time(time.time(), time_range)
        if valid_time_res == 1: # 在签到时间内
            if time.time() - time_range["StartTime"] > 10 * 60:
                # 刷新时间范围
                sign_info = await yb.task_feedback.get_sign_task()
                time_range = sign_info["Range"]
                if sign_info["State"] != 0:
                    # 非可签到状态
                    yb.log.info(f'非可签到状态: {sign_info.get("Msg")}')
                    await notice.send(f'{yb.get_user_name()} 非可签到状态，退出任务: {sign_info.get("Msg")}')
                    break
                sign_delay = random.randint(1 * 60, 10 * 60)
                yb.log.info(f'超过最大容忍时间，将在{timestamp_to_text(time.time() + sign_delay)}自动签到')
                await notice.send(f'超过最大容忍时间，将在{timestamp_to_text(time.time() + sign_delay)}自动签到')
                await asyncio.sleep(sign_delay)
                sign_data = user["signDataStr"] if user.get("signDataStr") else generate_sign_data_by_userconfig(user["signChoices"])
                yb.log.info(f'使用签到数据 {sign_data}')
                result = await yb.submit_sign_feedback(sign_data)
                if result["data"] is True:
                    await notice.send(f'{yb.get_user_name()} {result["msg"]}签到成功')
                    break
                else:
                    await notice.send(f'{yb.get_user_name()} {result["msg"]}')
                    break
            elif time_range["EndTime"] - time.time() < 20 * 60:
                yb.log.info(f'发送签到提醒')
                await notice.send(f'现在是北京时间{timestamp_to_text(time.time())}，{yb.user["name"]}还没有签到')
            yb.log.info(f'继续等待5分钟')
            await asyncio.sleep(5 * 60)
        elif valid_time_res == 0: # 未到签到时间
            yb.log.info(f'未到签到时间，继续等待至7点')
            await wait_until_specific_hour(7)
        elif valid_time_res == 2: # 已过签到时间
            yb.log.info(f'已过签到时间，退出任务')
            await notice.send(f'{yb.get_user_name()} 已过签到时间，退出任务')
            break
            # await wait_until_specific_hour(6)
            # refresh_sign_task_flag = True
    # 任务完毕
    return

async def immediately_sign(user: dict):
    async with Yiban(user["phone"], user["password"], logger) as yb:
        yb.log.info("登录成功")
        sign_data = user["signDataStr"] if user.get("signDataStr") else generate_sign_data_by_userconfig(
            user["signChoices"])
        yb.log.info(f'使用签到数据 {sign_data}')
        # 随即延迟1-10 sec
        await asyncio.sleep(random.randint(1, 10))
        result = await yb.submit_sign_feedback(sign_data)
        if result["data"] is True:
            yb.log.info("签到成功")
        else:
            yb.log.warning("签到失败: "+result["msg"])
        return

async def main():
    if not os.path.exists('./data'):
        os.mkdir('./data')
    if not os.path.exists('./data/user_cache'):
        os.mkdir('./data/user_cache')
    tasks: list[Coroutine] = []
    for i in users:
        if i.get("enable", True) is True:
            if "sign" in sys.argv:
                tasks.append(immediately_sign(i))
            else:
                tasks.append(create_user_task(i))
    await asyncio.gather(*tasks)

if __name__ == '__main__':
    logger.info("脚本已经启动")
    asyncio.run(main())